# @Version        : 1.0
# @Update Time    : 2025/2/8 22:01
# @File           : base_controller.py
# @IDE            : PyCharm
# @Desc           : 基础控制器，提供通用的响应处理和用户信息获取功能

from typing import Optional, TypeVar, Any, List, Union
from fastapi import Request
from fastapi_utils.camelcase import snake2camel
from sqlalchemy import ColumnElement
from sqlalchemy.orm import joinedload, selectinload
from sqlalchemy.ext.asyncio import AsyncSession

from src.common.enum import DateScopeEnum
from src.core.base.data_scope import ORM
from src.core.context_manager.user_utils import UserContextUtils
from src.core.exception import HttpCode
from src.core.response import ResponseSchema
from src.core.response.response_schema import (
    PageResponseDataSchema,
    ResponseGenericSchema,
)
from src.models import SysUser
from src.schemas.user_info_schema import UserInfo
from src.services.user_service import UserService

DataT = TypeVar("DataT", bound=Optional[Any])


class BaseController:
    """基础控制器类，提供通用的响应处理和用户信息获取功能"""

    request: Request

    @staticmethod
    def _response(
        *,
        data: DataT = None,
        resp: HttpCode = HttpCode.SUCCESS,
        msg: Optional[str] = None,
        code: Optional[int] = None,
        success: bool = True,
    ) -> Union[ResponseSchema, ResponseGenericSchema]:
        """
        构建统一响应格式

        Args:
            data: 响应数据
            resp: HTTP响应码枚举
            msg: 响应消息
            code: 响应状态码

        Returns:
            Union[ResponseSchema, ResponseGenericSchema]: 统一响应对象
        """
        return ResponseSchema(
            code=code or resp.code, msg=msg or resp.msg, data=data, success=success
        )

    def success(
        self,
        message: Optional[str] = None,
        *,
        code: Optional[int] = None,
        data: DataT = None,
        resp: HttpCode = HttpCode.SUCCESS,
    ) -> ResponseSchema:
        """
        成功响应

        Args:
            message: 响应消息
            code: 响应状态码
            data: 响应数据
            resp: HTTP响应码枚举

        Returns:
            ResponseSchema: 成功响应对象
        """
        return self._response(data=data, resp=resp, msg=message, code=code)

    def error(
        self,
        message: Optional[str] = None,
        *,
        code: Optional[int] = None,
        data: DataT = None,
        fail: HttpCode = HttpCode.FAILED,
    ) -> ResponseSchema:
        """
        错误响应

        Args:
            message: 响应消息
            code: 响应状态码
            data: 响应数据
            fail: HTTP响应码枚举

        Returns:
            ResponseSchema: 错误响应对象
        """
        return self._response(data=data, resp=fail, msg=message, code=code)

    def paginated_response(
        self,
        data: Optional[DataT] = None,
        total: int = 0,
        current: int = 1,
        size: int = 10,
        msg: Optional[str] = "操作成功",
    ) -> ResponseGenericSchema:
        """
        分页响应

        Args:
            data: 分页数据
            total: 总记录数
            current: 当前页码
            size: 每页大小
            msg: 响应消息

        Returns:
            ResponseGenericSchema: 分页响应对象
        """
        page_data = PageResponseDataSchema(
            records=data,
            total=total,
            current=current,
            size=size,
        )
        return self._response(data=page_data, msg=msg)

    @property
    def get_user_info(self) -> Optional[UserInfo]:
        """
        获取当前用户信息

        Returns:
            Optional[UserInfo]: 用户信息对象
        """
        return UserContextUtils.get_user_info()

    async def get_current_user(
        self, db: AsyncSession, login_id: Optional[Any] = None
    ) -> SysUser:
        login_id = login_id if login_id else self.request.state.login_id
        user = await UserService(db).get_one_or_none(
            SysUser.id == int(login_id),
            load=[SysUser.dept, selectinload(SysUser.roles).subqueryload("*")],
        )
        return user

    @property
    def get_user_id(self) -> Optional[int]:
        """
        获取当前用户ID

        Returns:
            Optional[int]: 用户ID
        """
        user_info = self.get_user_info
        return user_info.id if user_info else None

    @property
    def get_username(self) -> Optional[str]:
        """
        获取当前用户名

        Returns:
            Optional[str]: 用户名
        """
        user_info = self.get_user_info
        return user_info.username if user_info else None

    def camel_case(self, data: Any) -> Any:
        """
        将数据转换为驼峰命名格式

        Args:
            data: 需要转换的数据

        Returns:
            Any: 转换后的数据
        """
        if not data or isinstance(data, (str, int, float, bool)):
            return data

        if isinstance(data, dict):
            return {
                snake2camel(k, start_lower=True): self.camel_case(v)
                for k, v in data.items()
            }

        if isinstance(data, list):
            return [self.camel_case(item) for item in data]

        return data

    async def get_date_scope(
        self,
        model: ORM,
        user_alias: str = "user_id",
        dept_alias: str = "dept_id",
    ) -> List[ColumnElement]:
        """
        获取数据权限SQL过滤条件

        数据权限范围：
        0: 仅本人数据权限
        1: 本部门数据权限
        2: 本部门及以下数据权限
        3: 自定义数据权限
        4: 全部数据权限

        Args:
            model: ORM模型
            user_alias: 用户ID字段别名
            dept_alias: 部门ID字段别名

        Returns:
            List[ColumnElement]: SQL过滤条件列表
        """
        where: List[ColumnElement] = []
        user = self.get_user_info

        if not user:
            return [getattr(model, "id") == -1]  # 未登录用户无权限

        if user.is_super_admin():
            return []  # 超级管理员有全部权限

        if user.data_range == DateScopeEnum.SELF:
            # 仅本人数据权限
            if hasattr(model, user_alias):
                where.append(getattr(model, user_alias) == user.id)
            else:
                where.append(getattr(model, "id") == -1)

        elif user.data_range in (DateScopeEnum.DEPT, DateScopeEnum.DEPT_AND_CHILDREN):
            # 部门数据权限
            if hasattr(model, dept_alias):
                where.append(getattr(model, dept_alias).in_(user.dept_ids))
            else:
                where.append(getattr(model, "id") == -1)

        elif user.data_range == DateScopeEnum.ALL:
            return []  # 全部数据权限

        else:
            where.append(getattr(model, "id") == -1)  # 无权限

        return where
